import 'package:sleep/db/export.dart';
import 'package:sleep/single/analyze/base_analyze.dart';
import 'package:sleep/single/filter/base_filter.dart';
import 'package:sleep/single/point_model.dart';
import 'package:sleep/single/find_peak.dart';
import 'package:sleep/single/wave_show_model.dart';

class FatigueAnalyze extends BaseAnayze {
  final double minAmplitude;
  List<double> _orginData = [];
  List<FtaigueShowData> _waves = [];
  int _currentIndex = 0;

  @override
  List<double> get points => _orginData;
  @override
  List<FtaigueShowData> get waves => _waves;
  @override
  int get currentIndex => _currentIndex;

  FtaigueShowData? showModel;

  FatigueAnalyze(
      {required this.minAmplitude,
      required List<BaseFliter> fliter,
      required List<BaseFliter> showFliter})
      : super(fliter, showFliter);

  //蓝牙定时给数据
  @override
  insertData(List<double> data) {
    final filterData = toFilter(data); //对原始数据处理 滤波/限制
    timeIndex += 1;
    Export.share().save(filterData, CsvType.fatigue); //导出数据，保存原始数据
    _orginData.addAll(filterData); //展示波形的数据
    realtimeData(_orginData.length >= 15000
        ? _orginData.sublist(_orginData.length - 15000)
        : _orginData); //取最新 15000 个点计算
    _currentIndex += filterData.length;
  }

  int timeIndex = 0;
  //计算波形数据
  realtimeData(List<double> data) {
    //1s刷新一次
    if (timeIndex < 4) return;
    timeIndex = 0;
    List<SingeWaveModel> singWave =
        FatigueWaveFind().findWave(data, 0); //原始数据 转换为 一个个波峰波谷

    final List<FatigueWave> fwave = findFwave(singWave); //将波峰波谷合并成呼吸周期
    showModel = FtaigueShowData.fromWave(fwave); //多个呼吸动作 按权重取值 求的当前呼吸数据
    if (showModel != null) {
      _waves.add(showModel!); //波形数据
      Export.share().save(null, CsvType.fatiguewave,
          dataStr: [showModel!.toValue()]); //保存呼吸数据
    }

    clearOverData(); //清楚不要展示的数据
  }

  clearOverData() {
    if (_orginData.length > 16000) {
      _orginData = _orginData.sublist(_orginData.length - 15000);
    }
    if (_waves.length > 16000) {
      _waves = _waves.sublist(_waves.length - 15000);
    }
  }

//将闭眼睁眼 合并成 一个周期
  List<FatigueWave> findFwave(List<SingeWaveModel> waves) {
    final List<FatigueWave> fwave = [];
    if (waves.isEmpty) return fwave;
    FatigueWave? beforeWhole;
    SingeWaveModel? openEye; //睁眼
    SingeWaveModel? closeEye; //闭眼

    //遍历整睁眼闭眼 数据
    for (final wave in waves) {
      if (wave.type == FatigueWaveType.positive && closeEye != null) {
        //睁眼的前面必须有闭眼
        openEye ??= wave;
      } else if (wave.type == FatigueWaveType.negative) {
        closeEye = wave;
      }
      if (openEye != null && closeEye != null) {
        FatigueWave holeWave = FatigueWave(openEye, closeEye, beforeWhole);
        //添加到数组里面
        fwave.add(holeWave);
        openEye = null;
        closeEye = null;
        beforeWhole = holeWave;
      }
    }

    return fwave;
  }

  @override
  clear() {
    _orginData.clear();
    _waves.clear();
    _currentIndex = 0;
    showModel = null;
  }
}

class FatigueWaveFind {
  FatigueWaveFind();

//将一个个 数据 => [睁眼，闭眼]
  List<SingeWaveModel> findWave(List<double> data, double startIndex) {
    List<SingeWaveModel> waves = [];
    //找到波峰波谷,  halfwindowSize 表示要大于附近 点的 * 2个数
    List<WavePoint> peaks = PeakFind.findPeaks(data,
        halfwindowSize: 20, startIndex: startIndex.toInt());
    //差值平均值
    final average = _WaveAverge(peaks);
    for (int i = 1; i < peaks.length - 1; i++) {
      //遍历波峰波谷
      final current = peaks[i];
      final pre = peaks[i - 1];
      final end = peaks[i + 1];
      final leftAmp = current.y - pre.y;
      final rightAmp = current.y - end.y;

      final type = (leftAmp > 0.03 && rightAmp > 0.03 && current.y.abs() > 0.1)
          ? FatigueWaveType.positive
          : (leftAmp < -0.03 && rightAmp < -0.03 && current.y.abs() > 0.1)
              ? FatigueWaveType.negative
              : null; //判断当前点的值，和前后差值 来判断是闭眼还是睁眼

      if (type != null) {
        //筛选闭眼睁眼条件，过滤部分误判
        final isWave = isPeakWave(
            leftAmp,
            rightAmp,
            type == FatigueWaveType.positive
                ? average.positiveAverge
                : average.negativeAverge);
        if (isWave) {
          waves.add(
              SingeWaveModel(type: type, peak: current, start: pre, end: end));
        }
      }
    }
    return waves;
  }

  bool isPeakWave(double left, double right, double average) {
    const maxLRRate = 6;
    const minLRRate = 1 / maxLRRate;
    const averRate = 0.5;
    final lf = (left / right) < maxLRRate && (left / right) > minLRRate;
    final lfa = (left / average) > averRate && (right / average) > averRate;
    return lf && lfa;
  }
}

class _WaveAverge {
  final List<WavePoint> peaks;

  _WaveAverge(this.peaks) {
    findAverage(peaks);
  }

  final List<double> _positives = [];
  final List<double> _negatives = [];
  double get positiveAverge => _positives.isEmpty
      ? 0
      : _positives.reduce((a, b) => a + b) / _positives.length;

  double get negativeAverge => _negatives.isEmpty
      ? 0
      : _negatives.reduce((a, b) => a + b) / _negatives.length;
//睁闭眼的幅度计算的平均值
  findAverage(List<WavePoint> peaks) {
    for (int i = 1; i < peaks.length - 2; i++) {
      WavePoint prePeak = peaks[i - 1];
      WavePoint nextPeak = peaks[i + 1];
      WavePoint peak = peaks[i];
      double left = peak.y - prePeak.y;
      double right = peak.y - nextPeak.y;

      bool isA = _isAaverage(right / left);
      if (isA && left > 0) {
        _positives.add(left * 0.5 + right * 0.5);
      } else if (isA && left < 0) {
        _negatives.add(left * 0.5 + right * 0.5);
      }
    }
  }

  bool _isAaverage(double rate) {
    return rate <= 4 && rate >= 1 / 4;
  }
}
